package indi.zn.commons.threads.fork;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.RecursiveTask;
import java.util.function.Function;

/**
 * ForkJoin  Task
 * Used  ForkJoinPool
 * @author zn
 *
 * @param <R>
 */
public class AutoParallelPagedTask<R> extends RecursiveTask<R> {
	
	private static final long serialVersionUID = 1L;

	private Integer threshold;
	
	private Integer taskSize;
	
	private Integer turn;
	
	//No used
	private Integer parallelNum=5;
	
	private String taskId;
	
	private String taskName;
	
	private Object[] args;
	
	private Function<AutoParallelPagedTask<R>, R> executor;
	
	private Function<R, R> merge;

	private Integer forkLevel=1;
	
	private List<AutoParallelPagedTask<R>> forkList=new ArrayList<>();
	
	
	public AutoParallelPagedTask() {}
	
	public AutoParallelPagedTask(Integer threshold,Integer size,  Object[] args,Function<AutoParallelPagedTask<R>, R> executor) {
		super();
		this.threshold = threshold;
		this.taskSize=size;
		this.taskId =UUID.randomUUID().toString();
		this.taskName = "FJT:"+taskId;
		this.args = args;
		this.executor = executor;
	}
	
	
	public AutoParallelPagedTask(String taskId,String taskName, Integer threshold,Integer size,  Object[] args,
			Function<AutoParallelPagedTask<R>, R> executor) {
		super();
		this.threshold = threshold;
		this.taskId = taskId;
		this.taskName = taskName;
		this.args = args;
		this.executor = executor;
		this.taskSize=size;
	}

	
	public AutoParallelPagedTask(Integer threshold,Integer size,Object ... args) {
		super();
		this.threshold = threshold;
		this.taskSize=size;
		this.taskId =UUID.randomUUID().toString();
		this.args = args;
		this.taskSize=size;
	}
	
	
	public void initResult(R r) {
		
		setRawResult(r);

	}

	/**
	 * 主任务 执行函数
	 * @param func
	 */
	public void taskFunction(Function<AutoParallelPagedTask<R>, R> func) {
		
		this.executor=func;
		
	}
	
	/**
	 * 结果合并 函数
	 * @param merge
	 */
	public void mergeFunction(Function<R, R> merge) {
		
		this.merge=merge;
		
	}
	
	/**
	 * 自定义 拆分策略函数  未实现
	 */
	public void	forkStrategy(Function<AutoParallelPagedTask<R>, R> strategy){
		
		
		
	}
	
	
	
	public AutoParallelPagedTask<R> newFork(Integer size,Integer trun) {
	
		AutoParallelPagedTask<R> fjt=new AutoParallelPagedTask<>(threshold ,size ,args, executor);
		
		fjt.setTurn(trun);
		
		fjt.fork();
		
		forkList.add(fjt);
		
		return fjt;
	}

	/**
	 * 自动拆分任务 按 threshold 自动分页 最大并发 为parallelNum:5  ,单层 fork
	 */
	public boolean autoFork() {
		
		boolean forked=false;
		
		if(taskSize>threshold) {

			Integer forkTurn = taskSize/threshold +(taskSize%threshold ==0 ?0:1 ); 
		
		int parallelcount=0;
		
			
			for (int i = 0; i < forkTurn; i++) {
		
					newFork(threshold,i);
	
			}
			
			forked=true;

		}
		
		return forked;
		

	}
	 

	@Override
	protected R compute() {
		// TODO Auto-generated method stub
		 R r=null;
		
		if(autoFork()) {
			
			for (AutoParallelPagedTask<R> fjt : forkList) {
				
			 R jr=fjt.join();
			 
			 //System.out.println("task:"+fjt.getTaskId()+" join result:"+jr);
				
			 r=this.merge.apply(jr);
			 
			 if(r != getRawResult()) {
			  setRawResult(r);
			 }
			  
			}
				
		}else {
			
			r=executor.apply(this);
			
		}
		
		return r;
	}

	public Integer getThreshold() {
		return threshold;
	}

	public void setThreshold(Integer threshold) {
		this.threshold = threshold;
	}

	public Integer getTaskSize() {
		return taskSize;
	}

	public void setTaskSize(Integer taskSize) {
		this.taskSize = taskSize;
	}

	public Integer getTurn() {
		return turn;
	}

	public void setTurn(Integer turn) {
		this.turn = turn;
	}

	public String getTaskId() {
		return taskId;
	}

	public void setTaskId(String taskId) {
		this.taskId = taskId;
	}

	public String getTaskName() {
		return taskName;
	}

	public void setTaskName(String taskName) {
		this.taskName = taskName;
	}

	public Function<AutoParallelPagedTask<R>, R> getExecutor() {
		return executor;
	}

	public void setExecutor(Function<AutoParallelPagedTask<R>, R> executor) {
		this.executor = executor;
	}

	public Integer getForkLevel() {
		return forkLevel;
	}

	public void setForkLevel(Integer forkLevel) {
		this.forkLevel = forkLevel;
	}

	public List<AutoParallelPagedTask<R>> getForkList() {
		return forkList;
	}

	public void setForkList(List<AutoParallelPagedTask<R>> forkList) {
		this.forkList = forkList;
	}

	public Integer getParallelNum() {
		return parallelNum;
	}

	public void setParallelNum(Integer parallelNum) {
		this.parallelNum = parallelNum;
	}

	public Object[] getArgs() {
		return args;
	}

	public void setArgs(Object[] args) {
		this.args = args;
	}
	
	
	

}
